package Server;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Vector;

import Mailbox.Mailbox;
import Mailbox.MailboxFTP;

public class ChatRooms {

	private Vector<Socket> allParticipants;
	private Vector<String> allParticipantsNames;
	private HashMap<String, Vector<Socket>> participants;
	private HashMap<String, Mailbox> mailboxes;
	private HashMap<String, MailboxFTP> mailboxFTPCheckers;
	private HashMap<String, Thread> thread;
	private HashMap<String, Boolean> isPrivate;
	private HashMap<String, Vector<String>> userNames;
	private ServerSocket socket;

	public ChatRooms(ServerSocket socket) {
		participants = new HashMap<String, Vector<Socket>>();
		mailboxes = new HashMap<String, Mailbox>();
		mailboxFTPCheckers = new HashMap<String, MailboxFTP>();
		thread = new HashMap<String, Thread>();
		isPrivate = new HashMap<String, Boolean>();
		userNames = new HashMap<String, Vector<String>>();
		allParticipants = new Vector<Socket>();
		allParticipantsNames = new Vector<String>();
		this.socket = socket;
	}

	public synchronized boolean addPartToRoom(String room, Socket participant,
			String name) {

		if (participants.get(room) == null) {
			return false;
		}
		if (participants.get(room).contains(participant)) {
			return false;
		}
		if (isPrivate.get(room) && participants.get(room).size() >= 2) {
			send(participant, "Protocoll::Error,The private room is full!,"
					+ room);
			return false;
		}
		participants.get(room).add(participant);
		userNames.get(room).add(name);

		Vector<String> names = userNames.get(room);
		String message = "Protocol::GetNames," + room + ",";
		for (String s : names) {
			message += s + ",";
		}
		sendMessage(message, room, participant);

		return true;
	}

	public synchronized boolean removeParticipantFromRoom(String room,
			Socket participant, String name) {
		if (participants.containsKey(room)) {

			userNames.get(room).remove(name);

			Vector<String> names = userNames.get(room);
			String message = "Protocol::GetNames," + room + ",";
			for (String s : names) {
				message += s + ",";
			}
			if (!userNames.get(room).isEmpty()) {
				sendMessage(message, room, participant);
				participants.get(room).remove(participant);
			} else {
				mailboxes.get(room).saveMessage("IsToBeRemoved");
				String remove = "Protocol::RemoveRoom," + room;
				sendToAll(remove);
				participants.get(room).remove(participant);
				participants.remove(room);
				userNames.remove(room);
				thread.remove(room);
				mailboxes.remove(room);
				mailboxFTPCheckers.remove(room);
				isPrivate.remove(room);
			}

			return true;
		}
		return false;
	}

	public synchronized boolean createNew(String room, Socket participant,
			String name) {
		if (participants.containsKey(room)) {
			return false;
		}
		participants.put(room, new Vector<Socket>());
		userNames.put(room, new Vector<String>());
		isPrivate.put(room, false);
		mailboxFTPCheckers.put(room, new MailboxFTP());

		mailboxes.put(room, new Mailbox());
		thread.put(room, new MailboxChecker(room, this));
		thread.get(room).start();
		addPartToRoom(room, participant, name);
		sendToAll("Protocol::NewRoom," + room);
		return true;

	}

	private synchronized void sendToAll(String message) {
		if (allParticipants.size() != 0) {
			OutputStream os = null;
			for (Socket s : allParticipants) {
				try {
					os = s.getOutputStream();
					message = message + "\n";
					os.write(message.getBytes());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

	public synchronized boolean remove(String room) {
		if (participants.containsKey(room)) {
			participants.remove(room);
			userNames.remove(room);
			mailboxes.remove(room);
			sendToAll("Protocol::RemoveRoom," + room);
			return true;
		}
		return false;
	}

	public synchronized void sendMessage(String message, String room,
			Socket sender) {
		if (mailboxes.get(room) == null) {
			System.out.println(room + " DOES NOT EXIST!");
		} else if (!participants.get(room).contains(sender)) {
			System.out.println("THIS USER IS NOT PART OF THE ROOM " + room);
		} else {
			mailboxes.get(room).saveMessage(message);
		}
	}

	public synchronized Mailbox getMailbox(String room) {
		return mailboxes.get(room);
	}

	public synchronized Vector<Socket> getParticipants(String room) {

		return participants.get(room);
	}

	public synchronized Vector<String> getNames(String room) {

		return userNames.get(room);
	}

	public synchronized boolean createNewPrivate(String room,
			Socket participant, String name) {
		if (participants.containsKey(room)) {
			return false;
		}
		participants.put(room, new Vector<Socket>());
		userNames.put(room, new Vector<String>());
		isPrivate.put(room, true);
		mailboxFTPCheckers.put(room, new MailboxFTP());

		mailboxes.put(room, new Mailbox());
		thread.put(room, new MailboxChecker(room, this));
		thread.get(room).start();
		addPartToRoom(room, participant, name);
		sendToAll("Protocol::NewRoom," + room);
		return true;

	}

	public synchronized boolean addNewParticipants(Socket s, String name) {
		if (!allParticipantsNames.contains(name)) {
			allParticipantsNames.add(name);
			allParticipants.add(s);
			return true;
		} else {
			send(s, "Protocoll::Error,Username already in use!");
			return false;
		}
	}

	public synchronized void removeParti(Socket s, String name) {
		sendToAll("Protocol::RemoveName," + name);
		allParticipantsNames.remove(name);
		allParticipants.remove(s);
	}

	public synchronized void sendRooms(Socket s) {
		String message = "Protocol::sendAvailableRooms,";
		for (String room : participants.keySet()) {
			message += room + ",";
		}
		send(s, message);

	}

	public synchronized void sendParticipants(Socket s, String room) {
		Vector<String> names = userNames.get(room);
		String message = "Protocol::GetNames," + room + ",";
		for (String part : names) {
			message += part + ",";
		}
		send(s, message);
	}

	private synchronized void send(Socket s, String message) {
		OutputStream os = null;
		message += "\n";
		try {
			os = s.getOutputStream();
			os.write(message.getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public synchronized void sendAllNames(Socket s) {
		String message = "Protocol::AllNames,";
		for (String name : allParticipantsNames) {
			message += name + ",";
		}
		send(s, message);
	}

	public void updateAllNames() {
		for (Socket s : allParticipants) {
			sendAllNames(s);
		}

	}

	public void sendFileRequest(Socket s, String room) {
		String message = "Protocoll::StartFileRequest," + room;
		sendFileMessages(
				s,
				message,
				"Protocoll::Error, Can not find an partner to send the file too!",
				room);
	}

	public void sendFileNotAccepted(Socket s, String room) {
		String message = "Protocoll::Error,The file was not accepted by your partner!,";
		sendFileMessages(s, message,
				"Protocoll::Error,Error: Could not respond to your partner!!",
				room);
	}

	private void sendFileMessages(Socket s, String message, String error,
			String room) {
		Vector<Socket> part = participants.get(room);
		if (part.size() == 2) {
			if (part.get(0) != s) {
				send(part.get(0), message);
			} else {
				send(part.get(1), message);
			}
		} else {
			send(s, error);
		}
	}

	public void sendFileAccepted(Socket s, String room, String address) {
		String message = "Protocoll::AcceptedFile," + address;
		sendFileMessages(
				s,
				message,
				"Protocoll::Error,Error: The file was accepted but and error occured!",
				room);
	}

}
